package org.framework.common.api.query.expression;

import java.text.ParseException;
import java.util.Date;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.log4j.Logger;
import org.framework.common.api.query.Criterion;
import org.framework.common.api.query.QueryBean;
import org.framework.common.ext.util.DateUtil.DatePattern;
import org.framework.common.ext.util.StringUtil;

/**
 * 简单条件表达式
 * <p>描述: </p>
 * <p>Company: Professional</p>
 * 
 * @author chanlong(陈龙)
 * @date 2016年1月18日 下午4:52:24
 * @version 1.0.2016
 */
public class SimpleExpression implements Criterion {
	
	private Logger log = Logger.getLogger(SimpleExpression.class);
	
	private String 		fieldType; 		// 数据类型
	private String 		fieldName; 		// 属性名
	private Object 		fieldValue; 	// 对应值
	private Object[] 	fieldValues; 	// 对应值
	private Operator 	operator; 		// 计算符

	public SimpleExpression() {

	}
	
	public SimpleExpression(final QueryBean bean) {
		this.operator = Operator.valueOf(bean.getOperator());
		this.fieldType = bean.getFieldType();
		this.fieldName = bean.getFieldName();
		this.fieldValue = bean.getFieldValue();
		this.fieldValues = bean.getFieldValues();
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public Predicate toPredicate(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
		Path<?> expression = null;  
        if(fieldName.contains(".")){  
            String[] names = StringUtils.split(fieldName, ".");  
            expression = root.get(names[0]);  
            for (int i = 1; i < names.length; i++) {  
                expression = expression.get(names[i]);  
            }  
        }else{  
            expression = root.get(fieldName);  
        }  
          
        switch (operator) {
    		case IS_NOT_NULL:
    			return expression.isNotNull();
        	case IS_NULL:
        		return expression.isNull();
        	case NOT_IN:
        		return builder.not(expression.in(fieldValues));
        	case IN:  
        		return expression.in(fieldValues);
	        case EQ:  
	            return builder.equal(expression, fieldType == null ? fieldValue : parseValue(fieldValue, ValueType.valueOf(fieldType)));  
	        case NE:  
	            return builder.notEqual(expression, fieldValue);  
	        case LIKE:  
	            return builder.like((Expression<String>) expression, "%" + fieldValue + "%");  
	        case LIKE_L:  
	            return builder.like((Expression<String>) expression, "%" + fieldValue);  
	        case LIKE_R:  
	            return builder.like((Expression<String>) expression, fieldValue + "%");  
	        case LT:  
	            return builder.lessThan((Path<Comparable<Object>>)expression, fieldType == null ? (Comparable<Object>)fieldValue : parseValue(fieldValue, ValueType.valueOf(fieldType)));  
	        case GT:  
	            return builder.greaterThan((Path<Comparable<Object>>)expression, fieldType == null ? (Comparable<Object>)fieldValue : parseValue(fieldValue, ValueType.valueOf(fieldType)));  
	        case LE:  
	            return builder.lessThanOrEqualTo((Path<Comparable<Object>>)expression, fieldType == null ? (Comparable<Object>)fieldValue : parseValue(fieldValue, ValueType.valueOf(fieldType)));  
	        case GE:  
	        	return builder.greaterThanOrEqualTo((Path<Comparable<Object>>)expression, fieldType == null ? (Comparable<Object>)fieldValue : parseValue(fieldValue, ValueType.valueOf(fieldType)));
	        case BETWEEN:
				// 两者之间
				try{
					if(fieldValues.length == 2 && StringUtil.isNotEmpty(fieldType)){
						return builder.between((Path<Comparable<Object>>)expression, parseValue(fieldValues[0], ValueType.valueOf(fieldType)), parseValue(fieldValues[1], ValueType.valueOf(fieldType)));
					}	
				}catch (ClassCastException e) {
					throw new ClassCastException("非法的查询值:" + fieldValues);
				}
	        default:  
	            return builder.equal(expression, fieldValue);  
        }  
	}
	
	@SuppressWarnings("unchecked")
	private Comparable<Object> parseValue(final Object value, final ValueType type){
		try {
			switch (type) {
				case DATES:
				case DATETIMES:{
					Date date = DateUtils.parseDate(String.valueOf(value), DatePattern.DATE.value(), DatePattern.DATETIME.value());
					return (Comparable<Object>)(Object)date;
				}
				default: return (Comparable<Object>)value;
			}
		} catch (ParseException e) {
			e.printStackTrace();
			log.error("查询值类型转换失败：", e);
			return (Comparable<Object>)value;
		}
	}
	
	public String getFieldName() {
		return fieldName;
	}

	public void setFieldName(String fieldName) {
		this.fieldName = fieldName;
	}

	public Object getFieldValue() {
		return fieldValue;
	}

	public void setFieldValue(Object fieldValue) {
		this.fieldValue = fieldValue;
	}

	public Operator getOperator() {
		return operator;
	}

	public void setOperator(Operator operator) {
		this.operator = operator;
	}

}
